package com.buli.util.cron;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.support.CronExpression;

public class CronValidator {
    private static final Logger logger = LoggerFactory.getLogger(CronValidator.class);

    /**
     * Validates a Cron expression.
     *
     * @param cronExpression the Cron expression to validate
     * @return true if the Cron expression is valid, false otherwise
     */
    public static boolean isValidCron(String cronExpression) {
        if (cronExpression == null || cronExpression.isEmpty()) {
            logger.error("Cron expression is null or empty");
            return false;
        }

        String[] fields = cronExpression.split(" ");
        int expectedFields = 6; // Standard Cron expression has 6 fields

        // Check if it's a 7-field Cron expression
        if (fields.length == 7) {
            expectedFields = 7;
        } else if (fields.length != expectedFields) {
            logger.error("Invalid number of fields in Cron expression: {}", cronExpression);
            return false;
        }

        // Validate the year field if it exists
        if (expectedFields == 7) {
            String yearField = fields[6];
            if (!validateYearField(yearField)) {
                logger.error("Invalid year field in Cron expression: {}", cronExpression);
                return false;
            }
        }

        // Use Quartz to validate the Cron expression
        try {
             CronExpression.parse(cronExpression);
            return true;
        } catch (Exception e) {
            logger.error("Invalid Cron expression: {}", cronExpression, e);
            return false;
        }
    }

    /**
     * Validates the year field in a 7-field Cron expression.
     *
     * @param yearField the year field to validate
     * @return true if the year field is valid, false otherwise
     */
    private static boolean validateYearField(String yearField) {
        if (yearField == null || yearField.isEmpty()) {
            logger.error("Year field is null or empty");
            return false;
        }

        String[] yearParts = yearField.split(",");
        for (String part : yearParts) {
            if (!validateYearPart(part)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Validates a single part of the year field.
     *
     * @param yearPart the single part of the year field to validate
     * @return true if the year part is valid, false otherwise
     */
    private static boolean validateYearPart(String yearPart) {
        if (yearPart.contains("/")) {
            // Handle step values
            String[] stepParts = yearPart.split("/");
            if (stepParts.length != 2) {
                logger.error("Invalid step format in year field: {}", yearPart);
                return false;
            }
            if (!validateYear(stepParts[0]) || !validateStep(stepParts[1])) {
                return false;
            }
            int startYear = Integer.parseInt(stepParts[0]);
            int step = Integer.parseInt(stepParts[1]);
            while (startYear <= 2099) {
                if (startYear < 1970) {
                    logger.error("Year out of range after applying step: {}", startYear);
                    return false;
                }
                startYear += step;
            }
        } else if (yearPart.contains("-")) {
            // Handle ranges
            String[] rangeParts = yearPart.split("-");
            if (rangeParts.length != 2) {
                logger.error("Invalid range format in year field: {}", yearPart);
                return false;
            }
            if (!validateYear(rangeParts[0]) || !validateYear(rangeParts[1])) {
                return false;
            }
            int startYear = Integer.parseInt(rangeParts[0]);
            int endYear = Integer.parseInt(rangeParts[1]);
            if (startYear > endYear) {
                logger.error("Start year is greater than end year in range: {}", yearPart);
                return false;
            }
        } else {
            // Handle single years
            if (!validateYear(yearPart)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Validates a single year value.
     *
     * @param yearStr the year value as a string
     * @return true if the year is valid, false otherwise
     */
    private static boolean validateYear(String yearStr) {
        try {
            int year = Integer.parseInt(yearStr);
            // Quartz supports years from 1970 to 2099
            if (year < 1970 || year > 2099) {
                logger.error("Year out of range: {}", year);
                return false;
            }
            return true;
        } catch (NumberFormatException e) {
            logger.error("Invalid year format: {}", yearStr, e);
            return false;
        }
    }

    /**
     * Validates a step value.
     *
     * @param stepStr the step value as a string
     * @return true if the step is valid, false otherwise
     */
    private static boolean validateStep(String stepStr) {
        try {
            int step = Integer.parseInt(stepStr);
            if (step <= 0) {
                logger.error("Step must be a positive integer: {}", step);
                return false;
            }
            return true;
        } catch (NumberFormatException e) {
            logger.error("Invalid step format: {}", stepStr, e);
            return false;
        }
    }

    public static void main(String[] args) {
        // 测试用例
        String[] testExpressions = {
            "0 0 1 * * ?",          // 有效
            "0 0 1 * * ? 2023",     // 有效
            "0 0 1 * * ? 2023-2025", // 有效
            "0 0 1 * * ? 2023/2",    // 有效
            "0 0 1 * * ? 2023,2025,2027", // 有效
            "0 0 1 * * ? 2023HJ",   // 无效
            "0 0 1 * * ? 1899",     // 无效
            "0 0 1 * * ? 2100",     // 无效
            "0 0 1 * * *",          // 无效（缺少星期字段）
            "0 0 1 * * ? 2023 2024" // 无效（多余字段）
        };

        for (String cronExpression : testExpressions) {
            if (isValidCron(cronExpression)) {
                System.out.println("Cron表达式有效: " + cronExpression);
            } else {
                System.out.println("Cron表达式无效: " + cronExpression);
            }
        }
    }
}
